#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import sys
import codecs
import re

import time
from xml.dom import minidom

import old_date
import pascha

Conv = old_date.Old()
Pascha = pascha.Calc_p()

class ChangeDate():
    def __init__(self):
        
        self.today = []
        [self.today.append(time.localtime()[i]) for i in range(3)[::-1]]
        
    def m_range(self, year):

        return [31, Conv.visokos(year), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

    def calc_east(self, year=None):
        """Calculate feasts, depending on Easter date."""
        
        p_dates_y = []        

        if not year:
            year = self.today[2]

        p_date = Pascha.gogo(year)

        if debug:
            print 'pascha', p_date

        mytar = self.changer(p_date, -70) 
        verb = self.changer(p_date, -7) 
        prosh = self.changer(p_date, -49) 
        voznes = self.changer(p_date, 39) 
        trinity = self.changer(p_date, 49) 
        
        p_dates_y.append((mytar, "Неделя о мытаре и фарисее"))
        p_dates_y.append((prosh, "Прощенное Воскресенье"))
        p_dates_y.append((verb, "Вербное Воскресенье"))
        p_dates_y.append((p_date, "Пасха Христова"))
        p_dates_y.append((voznes, "Вознесение Господне"))
        p_dates_y.append((trinity, "Святая Троица"))


        return p_dates_y

    def count_diff(self, date1, date2):
        """Count range between dates"""

#        if debug:
#            print 'date1 %s, date2 %s' % (date1, date2)
#            sys.exit(1) #####dont forget!!!

        day1 = date1[0]
        month1 = date1[1]
        year1 = date1[2]
        
        day2 = date2[0]
        month2 = date2[1]
        year2 = date2[2]

        count = 0
        weeks = 0
        days_all = 0
        year = year1
        month = month1

        while True:
            m_range1 = self.m_range(year)

            for m_c in range(len(m_range1[month - 1:])):
                if m_c == 0 and year == year1:
                    inc = day1 - 1 
                else:
                    inc = 0
#                print 'days in month: ',  range(m_range1[month + m_c - 1])[inc:]
#                print 'month count: ',  month + m_c - 1

                for day in range(m_range1[month + m_c - 1])[inc:]:
#                    print 'day ', day

                    if count > 6:
                        weeks += 1
                        count = 0
#                    print 'month_a', month1 + m_c
                    
                    if day + 1 == day2 and month + m_c == month2 and year == year2:

                        # days between dates, weeks, tail - use for week days
                        return (days_all, weeks, count)
                    count += 1
                    days_all += 1

            year += 1
            month = 1
                    
        return 1

    def calc_week_bounds(self, date=None):
        """Calc upper and lower bounds of the current week"""

        if not date:
            date = self.today
        # epoch seconds
        ep_sec = time.mktime((date[2], date[1], date[0], 0, 0, 0, 0, 0, 0))
        weekday = time.localtime(ep_sec)[6]

        days = []
        curday = int(weekday)

        # first day of the current week
#        first = self.changer(self.today, -curday)
        first = self.changer(date, -curday)
        days.append(first)

        # find all dates for every weekday
        for dt in range(1,7):
            day = self.changer(first, dt)
            days.append(day)

        return days
     

    def calc_week(self, date=None):
        """Calculate name of the week since Easter, Pentecost, etc."""

        # Винмательно! Сначала - строка с описанием недели,
        # потом - тупль (неделя, остаток дней) - с Пасхи, Пятидесят...
        week_out = []  

        if date:
            year = date[2]
        else:
            date = Date_calc.today
            year = date[2] 

#        if debug:
#           print 'дата: ', date

        myt = Date_calc.calc_east(year)[0][0]
        eas = Date_calc.calc_east(year)[3][0]
        pent = Date_calc.calc_east(year)[5][0]

        if debug:
            print 'check myt, eas, pent', myt, eas, pent
        
        # from beginning of the year to myt and phar
        to_myt = Date_calc.count_diff((1, 1, year), myt)

        if debug:
            print 'check1'
        
        # to Easter
        to_eas = Date_calc.count_diff((1, 1, year), eas)
#        print to_eas

        # to Pentecost
        to_pent = Date_calc.count_diff((1, 1, year), pent)
#        print to_pent

        # to given day
        to_dat = Date_calc.count_diff((1, 1, year), date) 
#        print to_dat
        
        # Peter's fast
        to_pet = Date_calc.count_diff(pent, (12,7, year))
#        print 'Петров пост', to_pet[0] - 8

        
        # Неделя после пятидесятницы (счит от Пасхи этого года)
        if to_dat[0] > to_pent[0]:

            fr_pent = Date_calc.count_diff(pent, date)

            if fr_pent[2] == 0:
                week_out.append('Неделя ' + str(fr_pent[1] + 1) + '-я по Пятидесятнице.')
            else:
                week_out.append('Седмица ' + str(fr_pent[1] + 1) + '-я по Пятидесятнице.')

            week_out.append(fr_pent[1:])

            if debug:
                print fr_pent
                print 'Седмица ' + str(fr_pent[1] + 1) + '-я по Пятидесятнице.' 

        # Неделя после Пасхи нового года (до 50-цы)
        elif to_dat[0] >= to_eas[0] and to_dat[0] <= to_pent[0]:

            # (всего дней, недель, остаток дней - седмич) от Пасхи до текущей даты
            fr_eas = Date_calc.count_diff(eas, date)

            # Формат: (неделя с Пасхи, день седмицы)
            east_ls = [[(0, 0), ["Пасха. Светлое Христово Воскресение", '']], 
            [(0, 2), ['', 'Иверской иконы Божией Матери (переходящее празднование во вторник Светлой седмицы). Преподобномучеников отцев Давидо-Гареджийских (XVII) (Груз.) (переходящее празднование во вторник Светлой седмицы). Шуйской иконы Божией Матери (переходящее празднование во вторник Светлой седмицы).']], 
            [(0, 3), ['', 'Собор преподобных отцев, на Богошественной Горе Синай подвизавшихся (переходящее празднование в среду Светлой седмицы). Касперовской иконы Божией Матери (переходящее празднование в среду Светлой седмицы).']], 
            [(0,5), ['', 'Иконы Божией Матери "Живоносный Источник" (переходящее празднование в пятницу Светлой седмицы). Память обновления (освящения) храма Пресвятой Богородицы у Живоносного Источника в Константинополе (V) (переходящее празднование в пятницу Светлой седмицы). Иконы Божией Матери "Почаевской" (переходящее празднование в пятницу Светлой седмицы).']], 
            [(1, 0), ["Неделя 2-я по Пасхе, Антипасхи или ап.Фомы", '']], 
            [(2, 0), ['Неделя 3-я по Пасхе, св.жен-мироносиц, Глас вторый', '']], 
            [(3, 0), ['Неделя 4-я по Пасхе, о расслабленном, Глас третий', 'Перенесение мощей мч. Авраамия Болгарского (1230) (переходящее празднование в Неделю 4-ю по Пасхе). Прав. Тавифы (I) (переходящее празднование Неделю 4-ю по Пасхе).']], 
            [(4, 0), ['Неделя 5-я по Пасхе, о самаряныне, Глас четвертый.', '']], 
            [(5, 0), ['Неделя 6-я по Пасхе, о слепом, Глас пятый.', '']], 
            [(5, 3), ['Отдание св.Пасхи и предпразднство Вознесения Господня, Глас пятый.', '']], 
            [(5, 4), ['Вознесение Господа Бога и Спаса нашего Иисуса Христа, Глас пятый.', '']],
            [(6, 0), ['Неделя 7-я по Пасхе, Отцев I Вс.Собора, Глас шестый', 'Попразднство Вознесения Господня. Челнской иконы Божией Матери, именуемой "Умиление" (переходящее празднование в Неделю 7-ю по Пасхе).']],
            [(6, 5), ['Отдание Вознесения Господня, Глас шестый', 'Отдание праздника Вознесения Господня.']],
            [(6, 6), ['Троицкая родительская суббота, Глас шестый.', '']],
            [(7, 0), ['День Святой Троицы. Пятидесятница.', '']]]
#            if fr_eas[2] == 0 and fr_eas[1] == 1:
#                week_out.append('Неделя Фомина, или Антипасхи') 
#
            # Светлая Седмица
            if fr_eas[2] > 0 and fr_eas[1] == 0:
                week_out.append('Светлая седмица')
                week_out.append(fr_eas[1:])

            # Неделя N по Пасхе
            elif fr_eas[2] == 0 and fr_eas[1] > 1:
                week_out.append('Неделя ' + str(fr_eas[1]) + '-я по Пасце.')
                week_out.append(fr_eas[1:])

            # Седмица N по Пасхе
            else:
                week_out.append('Седмица ' + str(fr_eas[1] + 1) + '-я по Пасце.')
                week_out.append(fr_eas[1:])

            for i in range(len(east_ls)):
                # кол недель
                if fr_eas[1:] == east_ls[i][0]:
#                    print 'Праздник', east_ls[i][0]
                   # Если попала особая Неделя из списка, вычищаем 
                    if week_out:
                        week_out.pop()
                    week_out.append(east_ls[i][0])
                    week_out.append(fr_eas[1:])
                    
                    if east_ls[i][1][1]:
                        week_out.append(east_ls[i][1][1])

#            print 'fr_eas: ', fr_eas[1:] 

            if debug:
                print 'fr_eas: ', fr_eas[1:] 
#                print 'Седмица ' + str(fr_eas[1] + 1) + '-я по Пасце.' 

            
        # Период до недели Мытаря и Фар этого года.(старая Пятидесятница)
        elif to_dat[0] < to_myt[0]:
            # С прошлогодней Пасхи
            fr_old_eas = Date_calc.count_diff(Date_calc.calc_east(year - 1)[5][0], date)

            if fr_old_eas[2] == 0:
                week_out.append('Неделя ' + str(fr_old_eas[1] + 1) + '-я по Пятидесятнице.')
            else:
                week_out.append('Седмица ' + str(fr_old_eas[1] + 1) + '-я по Пятидесятнице.')

#            week_out.append('Седмица ' + str(fr_old_eas[1] + 1) + '-я по Пятидесятнице (стар.)')
            week_out.append(fr_old_eas[1:])

            if debug:
                print fr_old_eas, 'Седмица ' + str(fr_old_eas[1] + 1) + '-я по Пятидесятнице (стар.)'
                print 'old Pent: ', Date_calc.calc_east(year - 1)[5][0]

        # После Мыт и Фар до Пасхи
        elif to_dat[0] >= to_myt[0] and to_dat[0] < to_eas[0]:
            fr_myt_to_eas = Date_calc.count_diff(myt, date)

            if debug:
                print fr_myt_to_eas 

            if fr_myt_to_eas[1] == 0:
                if fr_myt_to_eas[2] == 0:
                    week_out.append('Неделя о мытаре и фарисее')

                    if debug:
                        print 'Неделя о мытаре и фарисее'
                else:
                    week_out.append('Седмица 1-я предуготовительная')
                    if debug:
                        print 'Седмица 1-я предуготовительная'
            elif fr_myt_to_eas[1] == 1:
                if fr_myt_to_eas[2] == 0:
                    week_out.append('Неделя о блудном сыне')
                    if debug:
                        print 'Неделя о блудном сыне'
                else:
                    week_out.append('Седмица 2-я предуготовительная')
                    if debug:
                        print 'Седмица 2-я предуготовительная'
            elif fr_myt_to_eas[1] == 2:
                if fr_myt_to_eas[2] == 0:
                    weel_out.append('Неделя о Страшном Суде (мясопустная)')
                    if debug:
                        print 'Неделя о Страшном Суде (мясопустная)'
                else:
                    week_out.append('Седмица 3-я предуготовительная (сырная)')
                    if debug:
                        print 'Седмица 3-я предуготовительная (сырная)'
            elif fr_myt_to_eas[1] > 2 and fr_myt_to_eas[1] < 8:
                if debug:
                    if debug:
                        print fr_myt_to_eas
                if fr_myt_to_eas[2] == 0:
                    week_out.append('Неделя ' + str(fr_myt_to_eas[1] - 2) + '-я Великого Поста')
                    if debug:
                        print 'Неделя ' + str(fr_myt_to_eas[1] - 2) + '-я Великого Поста'
                else:
                    week_out.append('Седмица ' + str(fr_myt_to_eas[1] - 2) + '-я Великого Поста')
                    if debug:
                        print 'Седмица ' + str(fr_myt_to_eas[1] - 2) + '-я Великого Поста'

            elif fr_myt_to_eas[1] > 2 and fr_myt_to_eas[1] == 8:
                if fr_myt_to_eas[2] == 6:
                    week_out.append('Лазарева суббота, воскрешение праведного Лазаря.')
                    if debug:
                        print 'Лазарева суббота, воскрешение праведного Лазаря.'
                elif fr_myt_to_eas[2] == 0:
                    week_out.append('Неделя 5-я Великого Поста')
                    if debug:
                        print 'Неделя 5-я Великого Поста'
                else:
                    week_out.append('Седмица 6-я Великого Поста (ваий)')
                    if debug:
                        print 'Седмица 6-я Великого Поста (ваий)'

#                    print 'Неделя Ваий, 6-я Великого Поста, Вход Господень в Иерусалим' 
#            print 'weeks since myt: ', fr_myt_to_eas, fr_myt_to_eas[1] + 1

            # Не забываем (недель, остав дней) с начала Поста
            week_out.append(fr_myt_to_eas[1:])

        return week_out


#    print 'Easter', Date_calc.calc_east(2010)[0][0]
# to date of myt and phar
        if debug:
            print Date_calc.count_diff((1, 1, 2010), Date_calc.calc_east(2010)[0][0])
# to date of Easter
        if debug:
            print Date_calc.count_diff((1, 1, 2010), Date_calc.calc_east(2010)[3][0])
# to given date
        if debug:
            print Date_calc.count_diff((1, 1, 2010), (16, 2, 2010))
# from myt till given day
        if debug:
            print 'to given day', Date_calc.count_diff(Date_calc.calc_east(2010)[0][0], (10, 2, 2010))
        if debug:
            for i in Date_calc.calc_east():
                print i[0], i[1]



    def changer(self, date, inc):
        """calculate new date using an increment"""
        if debug:
            print 'date %s, inc %s' % (date, inc)
        day = date[0] 
        month = date[1]
        year = date[2]
        m_d_list = self.m_range(year)
#        if debug:
#            print m_d_list
        if inc > 0:        
            while inc > 0:
                day += 1
                if day > m_d_list[month - 1]: 
                    month += 1
                    if month > 12:
                        month = 1
                        year += 1
                    day = 1 
                
                inc -= 1

        elif inc < 0:
            while inc < 0:
                day -= 1
                if day == 0: 
                    month -= 1
                    if month == 0: 
                        month = 12
                        year -= 1
                    day = m_d_list[month - 1]
                
                inc += 1

        elif inc == 0:
            return date

#        print 'changed: ', day, month, year
        return (day, month, year)           

class Reader:
    def __init__(self):
        pass

    def fixer(self, name_ls):
        """ fixing date to sortable repr """

        n_name_ls = []
        for i in name_ls:
            if len(i) < 2:
                n_name_ls.append('0' + i)
            else:
                n_name_ls.append(i)
        return n_name_ls

    def read(self, date_new):
        """ Read strings from file """
        
        date = Conv.to_old(date_new)
        f_name = '_'.join(self.fixer([str(z) for z in date][:2])) + '.xml'

#        fp = open('./clndlib/' + f_name, 'r')
        fp = open(os.path.join(os.path.expanduser('~'), 'coding/clndlib/', f_name), 'r')
#        lines = fp.readlines()
        xmldoc = minidom.parse(fp)
        fp.close()

        xml_nodes = xmldoc.getElementsByTagName('group')

        # convert Typicon signs back from latin letters
        s_list = [('(+)', 'b'), ('+)', 'v'), ('+', 'p'), ('с', 'g'), ('ш', 's')]

        m_names = ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря']
        d_names = ['Воскресенье,', 'Понедельник,', 'Вторник,', 'Среда,', 'Четверг,', 'Пятница,', 'Суббота,']

        day1 = date_new[0]
        month1 = date_new[1] - 1

        year1 = date_new[2]

        day2 = date[0]
        month2 = date[1] - 1

        year2 = date[2]
        
        week = Date_calc.calc_week(date_new)

        # Характеристика (напр, "Неделя N после Пасхи"
        print week[0]

        # "Сегодня" "день недели" "число" "месяц" "год - по нов. ст", (по старому)
        print today_word + d_names[week[1][1]], day1, m_names[month1], year1, "(", day2, m_names[month2], year2, "ст. ст. )"
#        print today_word, day1, m_names[month1], year1, "(", day2, m_names[month2], year2, "ст. ст. )"

        if debug:
            print 'week leng', len(week)
            print "week:"
            for entry in week:
                print entry

        # Читаем дневных святых
        for item in xml_nodes:
            if item.getAttribute('type') == 'normal':
                sign = item.getAttribute('sign')
                if sign:
                    for x in s_list:
                        if sign == x[1]:
                            sign = x[0]
#                print sign, item.firstChild.data
                tx = item.firstChild.data.encode('utf8')
                print sign, tx

if __name__ == '__main__':

    global debug
    debug = 0

    global date
    global today_word
    today_word = ''

    argv = sys.argv
    date = []
    data_list = []

    Date_calc = ChangeDate()
    Engine = Reader()

#    regspl = re.compile('-|/') 
#    regspl = re.compile('(\d?\d)?\/?(\d?\d)?\/?(\d\d\d\d)?')
#    regspl = re.compile('((\d?\d)\/(\d?\d)\/)|((\d?\d)\/(\d?\d)\/(\d\d\d\d))|((\d\d\d\d))')
    regch = re.compile('(?:(\d?\d)?\/?(\d?\d)?\/?(\d\d\d\d))|(?:(\d?\d)\/(\d?\d)\/?)')
#    regspl = re.compile('(?:(\d?\d)?(?:\/|-|:)?(\d?\d)?(?:\/|-|:)?(\d\d\d\d))|(?:(\d?\d)(?:\/|-|:)(\d?\d)(?:\/|-|:)?)')
    regspl = re.compile("(?:-|\/)") 

    from optparse import OptionParser
    usage = "usage: %prog [options] [day/month/year]"
    parser = OptionParser(usage=usage)

    parser.add_option("-t", "--tomorrow", dest="tomorrow", action='store_true', default=False, help="Get calendar entry for tomorrow")
    parser.add_option("-y", "--yesterday", dest="yesterday", action='store_true', default=False, help="Get calendar entry for yesterday")
    parser.add_option("-w", "--week", dest="week", action='store_true', default=False, help="Get calendar entries for a week")
    parser.add_option("-p", "--pascha", dest="pascha", action='store_true', default=False, help="Get dates for the feasts of Easter cycle")
    parser.add_option("-d", "--debug", dest="debug", action='store_true', default=False, help="Print debug info")
#    parser.add_option("-y", "--yesterday", dest="yesterday")

    (options, args) = parser.parse_args()

    if options.tomorrow and options.yesterday:
        parser.error("don't use -t and -y in one statement")
        sys.exit(1)
    elif options.tomorrow and args or options.yesterday and args:
        parser.error("don't use date arg with -t or -y option") 
        sys.exit(1)

    # есть дебаг 
    if options.debug:
        print '\ndebugger is on \n'
        debug = 1
    
    if args:
        if not regch.match(args[0]):
            print 'Bad date format'
            sys.exit(1) ##### do not forget!

        data_list = regspl.split(args[0])
#        if len(data_list) > 3:

        if len(data_list) == 3:
            [date.append(int(i)) for i in data_list]
        elif len(data_list) == 2:
            [date.append(int(i)) for i in data_list]
            date.append('')
        elif len(data_list) == 1:
            if len(data_list[0]) == 4:
                # not sure why i'm doing it.
                [date.append(x) for x in ('', '', data_list[0])]
    else:
        date = Date_calc.today

    if debug:
        print 'data_list %s, date %s' % (data_list, date)

    # есть опция вчера
    if options.yesterday:
        print 'Вчера'
        date = Date_calc.changer(date, -1)                        
        Engine.read(date)
        if debug:
            print '-y read'

    # есть опция завтра
    elif options.tomorrow:
        print 'Завтра'
        date = Date_calc.changer(date, 1)                        
        Engine.read(date)
        if debug:
            print '-t read'

    # есть неделя
    elif options.week:
        bound = Date_calc.calc_week_bounds(date)
        for day in bound:
            Engine.read(day)
            print "\n"
        if debug:
            print '-w read'

    # запрос на вывод праздников Пасхального круга
    elif options.pascha:
        east = Date_calc.calc_east(int(date[2]))

        for feast in east:
            print feast[1], feast[0], '\n'

    # Нет аргументов
    else:
        if not args:
            today_word = 'Сегодня, '
            Engine.read(date)
            if debug:
                print 'no args no opts, read'
        else:
            Engine.read(date)
            if debug:
                print 'no opts, only args, read'


    if debug:
        print "options %s, args %s" % (options, args)
#        Date_calc.calc_week((30,1,2008))
    #    Date_calc.calc_week((24,1,2010))
    #    Date_calc.calc_week((11,4,2009))
    #    Date_calc.calc_week((8,3,2009))
    #    Date_calc.calc_week((24,5,2010))

#    for x, y in Date_calc.calc_east(2010):
#        print x, y 

# TODO: make whole year
# TODO: integrate with calendar.py
# TODO: output in text/html ^^^
